Back to Blog Tutorial

The Form Processor: Using Only SQL

The forms are built. Now see how easy it is to process them — all it takes is a SQL query for each one, insert or update.

Jul 2005·6 min read·Post 7 of 8

Here, there's no HTML structure needed at all — just a Dvl-epr component, formajaxsave, along with the insert or update SQL it needs to run.

1 Adding a Contact
emxml_ajxPrcInsertContact.xml
<Block tag='none'>

    <Element type='formajaxsave'>
    <n>insertcontact</n>
    <SQL>
        <query name='newcontact' success='Contact saved.' fail='Could not save contact.'>
            <![CDATA[
                INSERT INTO contacts
                    (dept_id, contact_name, email, department, phone, status, created_date)
                VALUES
                    ('%deptid%', '%contact_name%', '%email%', '%department%', '%phone%', 'Active', NOW())
            ]]>
        </query>

        <query name='retInfo' type='data'>
            <![CDATA[
                SELECT '%newcontact_id%' AS contact_id,
                       '%contact_name%' AS contact_name,
                       'CONTACTADDED' AS TYPE
                FROM DUAL
            ]]>
        </query>
    </SQL>
    </Element>

</Block>
2 Updating a contact

The Update form's processor follows the exact same shape — same <Block tag='none'>, same formajaxsave wrapper, same retInfo pattern — just an UPDATE in place of an INSERT, filtered to the one row being edited:

emxml_ajxPrcUpdateContact.xml
<Block tag='none'>
     
        <Element type='formajaxsave'>
        <n>updatecontact</n>
        <SQL>
            <query name='updatedcontact' success='Contact updated.' fail='Could not update contact.'>
                <![CDATA[
                    UPDATE contacts
                    SET    contact_name = '%contact_name%',
                           email = '%email%',
                           department = '%department%',
                           phone = '%phone%'
                    WHERE  contact_id = '%contact_id%'
                    AND    dept_id = '%deptid%'
                ]]>
            </query>
     
            <query name='retInfo' type='data'>
                <![CDATA[
                    SELECT '%contact_id%' AS contact_id,
                           '%contact_name%' AS contact_name,
                           'CONTACTUPDATED' AS TYPE
                    FROM DUAL
                ]]>
            </query>
        </SQL>
        </Element>
     
    </Block>
WHERE contact_id
The one genuinely new piece here — the %contact_id% that post 6's hidden field carried out of the Edit form comes back in as the filter, so the update lands on exactly the row that was opened, and no other.

And sendEmail() itself, inside eminc_contactfunctions.inc:

PHP function contract
<?php
    function sendEmail($parmlist) {
        // $parmlist holds every token in scope, including newcontact_id from the query above
        $email = $parmlist['email'];
     
        // ... send the email ...
     
        return '';  // empty string = success
        // throw new Exception('Could not send welcome email');  // failure
    }

Return an empty string for success, throw an exception for failure — that's the entire contract. Everything else (the response, the message shown to the user) works exactly the same whether the step in between was a query or a function.

3 What happens, start to finish
1
User clicks Save Contact in the form.
2
The processor is called.
3
The SQL — and any plugin functions — execute.
4
The processor sends the response back.
5
The user sees a confirmation, and the contacts list reflects the new row — zero hand-written JavaScript for any of it.
4 Rendered live
app.example.com/manager/contacts
Contact saved.
Sarah Whitfield  ·  Operations
David Okonkwo  ·  Procurement
Priya Anand  ·  Customer Service Just added
Two forms, two processors, an insert and an update — built across two posts, without writing a single AJAX call by hand.

That's the full read-and-write loop the platform runs on: a list or table to browse, a detail screen to focus on one record, forms to add and update it, processors to save it. Every other screen on the platform is some combination of these same pieces. The last post in this arc puts all of them on one page together.